home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 001-100 / 001-025 / 008 / src / hack.invent.c < prev    next >
C/C++ Source or Header  |  1995-03-17  |  17KB  |  704 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
  2.  
  3. #include   "hack.h"
  4. #include   <stdio.h>
  5. #undef max
  6.  
  7. extern struct obj *splitobj();
  8. extern char morc;
  9. #ifndef NOWORM
  10. #include   "def.wseg.h"
  11.  
  12. extern struct wseg *wsegs[32];
  13. #endif NOWORM
  14.  
  15. struct obj *
  16. addinv(obj) register struct obj *obj; {
  17.    register struct obj *otmp;
  18.    for(otmp = invent; otmp; otmp = otmp->nobj) {
  19.       if(merged(otmp, obj, 0)) return(otmp);
  20.       if(!otmp->nobj) {
  21.          otmp->nobj = obj;
  22.          obj->nobj = 0;
  23.          return(obj);
  24.       }
  25.    }
  26.    invent = obj;
  27.    obj->nobj = 0;
  28.    return(obj);
  29. }
  30.  
  31. useup(obj)
  32. register struct obj *obj;
  33. {
  34.    if(obj->quan > 1){
  35.       obj->quan--;
  36.       obj->owt = weight(obj);
  37.    } else {
  38.       setnotworn(obj);
  39.       freeinv(obj);
  40.       obfree(obj, (struct obj *) 0);
  41.    }
  42. }
  43.  
  44. freeinv(obj) register struct obj *obj; {
  45.    register struct obj *otmp;
  46.    if(obj == invent) invent = invent->nobj;
  47.    else {
  48.       for(otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
  49.          if(!otmp->nobj) panic("freeinv");
  50.       otmp->nobj = obj->nobj;
  51.    }
  52. }
  53.  
  54. /* destroy object in fobj chain (if unpaid, it remains on the bill) */
  55. delobj(obj) register struct obj *obj; {
  56.    freeobj(obj);
  57.    unpobj(obj);
  58.    obfree(obj, (struct obj *) 0);
  59. }
  60.  
  61. /* unlink obj from chain starting with fobj */
  62. freeobj(obj) register struct obj *obj; {
  63.    register struct obj *otmp;
  64.  
  65.    if(obj == fobj) fobj = fobj->nobj;
  66.    else {
  67.       for(otmp = fobj; otmp->nobj != obj; otmp = otmp->nobj)
  68.          if(!otmp) panic("error in freeobj");
  69.       otmp->nobj = obj->nobj;
  70.    }
  71. }
  72.  
  73. /* Note: freegold throws away its argument! */
  74. freegold(gold) register struct gen *gold; {
  75.    register struct gen *gtmp;
  76.  
  77.    if(gold == fgold) fgold = gold->ngen;
  78.    else {
  79.       for(gtmp = fgold; gtmp->ngen != gold; gtmp = gtmp->ngen)
  80.          if(!gtmp) panic("error in freegold");
  81.       gtmp->ngen = gold->ngen;
  82.    }
  83.    free((char *) gold);
  84. }
  85.  
  86. deltrap(trap)
  87. register struct gen *trap;
  88. {
  89.    register struct gen *gtmp;
  90.  
  91.    if(trap==ftrap) ftrap=ftrap->ngen;
  92.    else {
  93.       for(gtmp=ftrap;gtmp->ngen!=trap;gtmp=gtmp->ngen) ;
  94.       gtmp->ngen=trap->ngen;
  95.    }
  96.    free((char *) trap);
  97. }
  98.  
  99. struct wseg *m_atseg;
  100.  
  101. struct monst *
  102. m_at(x,y)
  103. register int x,y;
  104. {
  105.    register struct monst *mtmp;
  106. #ifndef NOWORM
  107.    register struct wseg *wtmp;
  108. #endif NOWORM
  109.  
  110.    m_atseg = 0;
  111.    for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
  112.       if(mtmp->mx == x && mtmp->my == y)
  113.          return(mtmp);
  114. #ifndef NOWORM
  115.       if(mtmp->wormno){
  116.           for(wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg)
  117.           if(wtmp->wx == x && wtmp->wy == y){
  118.          m_atseg = wtmp;
  119.          return(mtmp);
  120.           }
  121.       }
  122. #endif NOWORM
  123.    }
  124.    return(0);
  125. }
  126.  
  127. struct obj *
  128. o_at(x,y)
  129. register int x,y;
  130. {
  131.    register struct obj *otmp;
  132.  
  133.    for(otmp = fobj; otmp; otmp = otmp->nobj)
  134.       if(otmp->ox == x && otmp->oy == y) return(otmp);
  135.    return(0);
  136. }
  137.  
  138. struct obj *
  139. sobj_at(n,x,y)
  140. register int n,x,y;
  141. {
  142.    register struct obj *otmp;
  143.  
  144.    for(otmp = fobj; otmp; otmp = otmp->nobj)
  145.       if(otmp->ox == x && otmp->oy == y && otmp->otyp == n)
  146.          return(otmp);
  147.    return(0);
  148. }
  149.  
  150. carried(obj) register struct obj *obj; {
  151. register struct obj *otmp;
  152.    for(otmp = invent; otmp; otmp = otmp->nobj)
  153.       if(otmp == obj) return(1);
  154.    return(0);
  155. }
  156.  
  157. struct obj *
  158. o_on(id, objchn) unsigned int id; register struct obj *objchn; {
  159.    while(objchn) {
  160.       if(objchn->o_id == id) return(objchn);
  161.       objchn = objchn->nobj;
  162.    }
  163.    return((struct obj *) 0);
  164. }
  165.  
  166. struct gen *
  167. g_at(x,y,ptr)
  168. register int x,y;
  169. register struct gen *ptr;
  170. {
  171.    while(ptr) {
  172.       if(ptr->gx == x && ptr->gy == y) return(ptr);
  173.       ptr = ptr->ngen;
  174.    }
  175.    return(0);
  176. }
  177.  
  178. /* getobj returns:
  179.    struct obj *xxx:   object to do something with.
  180.    0            error return: no object.
  181.    1            explicitly no object (as in w-).
  182. */
  183. struct obj *
  184. getobj(let,word)
  185. register char *let,*word;
  186. {
  187.    register struct obj *otmp;
  188.    register char ilet,ilet1,ilet2;
  189.    char buf[BUFSZ];
  190.    char lets[BUFSZ];
  191.    register int foo = 0, foo2, cnt;
  192.    register char *bp = buf;
  193.    xchar allowcnt = 0;   /* 0, 1 or 2 */
  194.    boolean allowgold = FALSE;
  195.    boolean allowall = FALSE;
  196.    boolean allownone = FALSE;
  197.    xchar foox = 0;
  198.  
  199.    if(*let == '0') let++, allowcnt = 1;
  200.    if(*let == '$') let++, allowgold = TRUE;
  201.    if(*let == '#') let++, allowall = TRUE;
  202.    if(*let == '-') let++, allownone = TRUE;
  203.    if(allownone) *bp++ = '-';
  204.    if(allowgold) *bp++ = '$';
  205.    if(bp[-1] == '-') *bp++ = ' ';
  206.  
  207.    ilet = 'a';
  208.    for(otmp = invent; otmp; otmp = otmp->nobj){
  209.       if(!*let || index(let, otmp->olet)) {
  210.          bp[foo++] = ilet;
  211.          /* ugly check: remove inappropriate things */
  212.          if((!strcmp(word, "take off") &&
  213.              !(otmp->owornmask & (W_ARMOR - W_ARM2)))
  214.          || (!strcmp(word, "wear") &&
  215.              (otmp->owornmask & (W_ARMOR | W_RING)))
  216.          || (!strcmp(word, "wield") &&
  217.              (otmp->owornmask & W_WEP))) {
  218.             foo--;
  219.             foox++;
  220.          }
  221.       }
  222.       if(ilet == 'z') ilet = 'A'; else ilet++;
  223.    }
  224.    bp[foo] = 0;
  225.    if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
  226.    (void) strcpy(lets, bp);   /* necessary since we destroy buf */
  227.    if(foo > 5) {         /* compactify string */
  228.       foo = foo2 = 1;
  229.       ilet2 = bp[0];
  230.       ilet1 = bp[1];
  231.       while(ilet = bp[++foo2] = bp[++foo]){
  232.          if(ilet == ilet1+1){
  233.             if(ilet1 == ilet2+1)
  234.                bp[foo2 - 1] = ilet1 = '-';
  235.             else if(ilet2 == '-') {
  236.                bp[--foo2] = ++ilet1;
  237.                continue;
  238.             }
  239.          }
  240.          ilet2 = ilet1;
  241.          ilet1 = ilet;
  242.       }
  243.    }
  244.    if(!foo && !allowall && !allowgold && !allownone) {
  245.       pline("You don't have anything %sto %s.",
  246.          foox ? "else " : "", word);
  247.       return(0);
  248.    }
  249.    for(;;) {
  250.       if(!buf[0])
  251.          pline("What do you want to %s [*]? ", word);
  252.       else
  253.          pline("What do you want to %s [%s or ?*]? ",
  254.             word, buf);
  255.  
  256.       cnt = 0;
  257.       ilet = readchar();
  258.       while(digit(ilet) && allowcnt) {
  259.          cnt = 10*cnt + (ilet - '0');
  260.          allowcnt = 2;   /* signal presence of cnt */
  261.          ilet = readchar();
  262.       }
  263.       if(digit(ilet)) {
  264.          pline("No count allowed with this command.");
  265.          continue;
  266.       }
  267.       if(ilet == '\033' || ilet == ' ' || ilet == '\n')
  268.          return((struct obj *)0);
  269.       if(ilet == '-') {
  270.          return((struct obj *)(allownone ? 1 : 0));
  271.       }
  272.       if(ilet == '$') {
  273.          if(!allowgold){
  274.             pline("You cannot %s gold.", word);
  275.             continue;
  276.          }
  277.          otmp = newobj(0);
  278.          /* should set o_id etc. but otmp will be freed soon */
  279.          otmp->olet = '$';
  280.          if(allowcnt == 2 && cnt < u.ugold)
  281.             u.ugold -= cnt;
  282.          else {
  283.             cnt = u.ugold;
  284.             u.ugold = 0;
  285.          }
  286.          flags.botl = 1;
  287.          otmp->quan = cnt;
  288.          return(otmp);
  289.       }
  290.       if(ilet == '?') {
  291.          doinv(lets);
  292.          if(!(ilet = morc)) continue;
  293.          /* he typed a letter (not a space) to more() */
  294.       } else if(ilet == '*') {
  295.          doinv("");
  296.          if(!(ilet = morc)) continue;
  297.          /* ... */
  298.       }
  299.       if(ilet >= 'A' && ilet <= 'Z') ilet += 'z'-'A'+1;
  300.       ilet -= 'a';
  301.       for(otmp = invent; otmp && ilet; ilet--, otmp = otmp->nobj) ;
  302.       if(!otmp) {
  303.          pline("You don't have that object.");
  304.          continue;
  305.       }
  306.       if(cnt < 0 || otmp->quan < cnt) {
  307.          pline("You don't have that many! [You have %d]"
  308.          , otmp->quan);
  309.          continue;
  310.       }
  311.       break;
  312.    }
  313.    if(!allowall && let && !index(let,otmp->olet)) {
  314.       pline("That is a silly thing to %s.",word);
  315.       return(0);
  316.    }
  317.    if(allowcnt == 2) {   /* cnt given */
  318.       if(cnt == 0) return(0);
  319.       if(cnt != otmp->quan) {
  320.          register struct obj *obj;
  321.          obj = splitobj(otmp, cnt);
  322.          if(otmp == uwep) setuwep(obj);
  323.       }
  324.    }
  325.    return(otmp);
  326. }
  327.  
  328. ckunpaid(otmp) register struct obj *otmp; {
  329.    return( otmp->unpaid );
  330. }
  331.  
  332. /* interactive version of getobj */
  333. /* used for Drop and Identify */
  334. ggetobj(word, fn, max)
  335. char *word;
  336. int (*fn)(),  max;
  337. {
  338. char buf[BUFSZ];
  339. register char *ip;
  340. register char sym;
  341. register int oletct = 0, iletct = 0;
  342. register boolean allflag = FALSE;
  343. char olets[20], ilets[20];
  344. int (*ckfn)() = (int (*)()) 0;
  345.    if(!invent){
  346.       pline("You have nothing to %s.", word);
  347.       return(0);
  348.    } else {
  349.       register struct obj *otmp = invent;
  350.       register int uflg = 0;
  351.  
  352.       ilets[0] = 0;
  353.       while(otmp) {
  354.          if(!index(ilets, otmp->olet)){
  355.             ilets[iletct++] = otmp->olet;
  356.             ilets[iletct] = 0;
  357.          }
  358.          if(otmp->unpaid) uflg = 1;
  359.          otmp = otmp->nobj;
  360.       }
  361.       ilets[iletct++] = ' ';
  362.       if(uflg) ilets[iletct++] = 'u';
  363.       ilets[iletct++] = 'a';
  364.       ilets[iletct] = 0;
  365.    }
  366.    pline("What kinds of thing do you want to %s? [%s] ",
  367.       word, ilets);
  368.    getlin(buf);
  369.    ip = buf;
  370.    olets[0] = 0;
  371.    while(sym = *ip++){
  372.       if(sym == ' ') continue;
  373.       if(sym == 'a') allflag = TRUE; else
  374.       if(sym == 'u') ckfn = ckunpaid; else
  375.       if(index("!%?[()=*/\"0", sym)){
  376.          if(!index(olets, sym)){
  377.             olets[oletct++] = sym;
  378.             olets[oletct] = 0;
  379.          }
  380.       }
  381.       else pline("You don't have any %c's.", sym);
  382.    }
  383.    return askchain(invent, olets, allflag, fn, ckfn, max);
  384. }
  385.  
  386. /* Walk through the chain starting at objchn and ask for all objects
  387.    with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
  388.    whether the action in question (i.e., fn) has to be performed.
  389.    If allflag then no questions are asked. Max gives the max nr of
  390.    objects treated.
  391.  */
  392. askchain(objchn, olets, allflag, fn, ckfn, max)
  393. struct obj *objchn;
  394. register char *olets;
  395. int allflag;
  396. int (*fn)(), (*ckfn)();
  397. int max;
  398. {
  399. register struct obj *otmp, *otmp2;
  400. register char sym, ilet;
  401. register int cnt = 0;
  402.    ilet = 'a'-1;
  403.    for(otmp = objchn; otmp; otmp = otmp2){
  404.       if(ilet == 'z') ilet = 'A'; else ilet++;
  405.       otmp2 = otmp->nobj;
  406.       if(olets && *olets && !index(olets, otmp->olet)) continue;
  407.       if(ckfn && !(*ckfn)(otmp)) continue;
  408.       if(!allflag) {
  409.          prname(otmp, ilet, 1);
  410.          addtopl(" (ynaq)? ");
  411.          sym = readchar();
  412.       }
  413.       else   sym = 'y';
  414.  
  415.       switch(sym){
  416.       case 'a':
  417.          allflag = 1;
  418.       case 'y':
  419.          cnt += (*fn)(otmp);
  420.          if(--max == 0) goto ret;
  421.       case 'n':
  422.       default:
  423.          break;
  424.       case 'q':
  425.          goto ret;
  426.       }
  427.    }
  428.    pline(cnt ? "That was all." : "No applicable objects.");
  429. ret:
  430.    if(!flags.echo) echo(OFF);
  431.    return(cnt);
  432. }
  433.  
  434. obj_to_let(obj)
  435. register struct obj *obj;
  436. {
  437.    register struct obj *otmp;
  438.    register char ilet = 'a';
  439.  
  440.    for(otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
  441.       if(++ilet > 'z') ilet = 'A';
  442.    return(otmp ? ilet : 0);
  443. }
  444.  
  445. prinv(obj)
  446. register struct obj *obj;
  447. {
  448.    prname(obj, obj_to_let(obj), 1);
  449. }
  450.  
  451. prname(obj,let,onelin)
  452. register struct obj *obj;
  453. register char let;
  454. {
  455.    char li[BUFSZ];
  456.  
  457.    (void) sprintf(li, " %c - %s.", let, doname(obj));
  458.    switch(onelin) {
  459.    case 1:
  460.       pline(li+1);
  461.       break;
  462.    case 0:
  463.       myputs(li+1);
  464.       break;
  465.    case -1:
  466.       cl_end();
  467.       myputs(li);
  468.       curx += strlen(li);
  469.    }
  470. }
  471.  
  472. ddoinv()
  473. {
  474.    doinv((char *) 0);
  475.    return(0);
  476. }
  477.  
  478. myddoinv()
  479. {
  480.    mydoinv((char *) 0);
  481.    return(0);
  482. }
  483.  
  484. myprname(obj,let,onelin)
  485. register struct obj *obj;
  486. register char let;
  487. {
  488.    char li[BUFSZ];
  489.  
  490.    (void) sprintf(li, " %c - %s.", let, mydoname(obj));
  491.    switch(onelin) {
  492.    case 1:
  493.       pline(li+1);
  494.       break;
  495.    case 0:
  496.       myputs(li+1);
  497.       break;
  498.    case -1:
  499.       cl_end();
  500.       myputs(li);
  501.       curx += strlen(li);
  502.    }
  503. }
  504.  
  505. mydoinv(lets) register char *lets; {
  506.    register struct obj *otmp;
  507.    register char ilet = 'a';
  508.    int ct = 0;
  509.    int maxlth = 0;
  510.    int lth;
  511.  
  512.    if(!invent){
  513.       pline("Not carrying anything");
  514.       if(lets) return;
  515.    }
  516.    if(!flags.oneline) {
  517.        if(!lets || !*lets)
  518.       for(otmp = invent; otmp; otmp = otmp->nobj) ct++;
  519.        else
  520.       ct = strlen(lets);
  521.        if(ct > 1 && ct < ROWNO && (lets || !inshop())){
  522.       for(otmp = invent; otmp; otmp = otmp->nobj) {
  523.           if(!lets || !*lets || index(lets, ilet)) {
  524.          lth = strlen(doname(otmp));
  525.          if(lth > maxlth) maxlth = lth;
  526.           }
  527.           if(++ilet > 'z') ilet = 'A';
  528.       }
  529.       ilet = 'a';
  530.       lth = COLNO - maxlth - 7;
  531.       if(lth < 10) goto clrscr;
  532.       home();
  533.       cl_end();
  534.       flags.topl = 0;
  535.       ct = 0;
  536.       for(otmp = invent; otmp; otmp = otmp->nobj) {
  537.           if(!lets || !*lets || index(lets, ilet)) {
  538.          curs(lth, ++ct);
  539.          myprname(otmp, ilet, -1);
  540.           }
  541.           if(++ilet > 'z') ilet = 'A';
  542.       }
  543.       curs(lth, ct+1);
  544.       cl_end();
  545.       cmore();   /* sets morc */
  546.       /* test whether morc is a reasonable answer */
  547.       if(lets && *lets && !index(lets, morc)) morc = 0;
  548.  
  549.       home();
  550.       cl_end();
  551.       docorner(lth, ct);
  552.       return;
  553.        }
  554.    }
  555.     clrscr:
  556.    if(ct > 1) cls();
  557.    for(otmp = invent; otmp; otmp = otmp->nobj){
  558.       if(!lets || !*lets || index(lets, ilet))
  559.          myprname(otmp, ilet, (ct > 1) ? 0 : 1);
  560.       if(++ilet > 'z') ilet = 'A';
  561.    }
  562.    /* tell doinvbill whether we cleared the screen */
  563.    if(!lets) doinvbill((ct > 1));
  564.    if(ct > 1){
  565.       cgetret();
  566.       docrt();
  567.    } else
  568.       morc = 0;   /* %% */
  569. }
  570.  
  571. doinv(lets) register char *lets; {
  572.    register struct obj *otmp;
  573.    register char ilet = 'a';
  574.    int ct = 0;
  575.    int maxlth = 0;
  576.    int lth;
  577.  
  578.    if(!invent){
  579.       pline("Not carrying anything");
  580.       if(lets) return;
  581.    }
  582.    if(!flags.oneline) {
  583.        if(!lets || !*lets)
  584.       for(otmp = invent; otmp; otmp = otmp->nobj) ct++;
  585.        else
  586.       ct = strlen(lets);
  587.        if(ct > 1 && ct < ROWNO && (lets || !inshop())){
  588.       for(otmp = invent; otmp; otmp = otmp->nobj) {
  589.           if(!lets || !*lets || index(lets, ilet)) {
  590.          lth = strlen(doname(otmp));
  591.          if(lth > maxlth) maxlth = lth;
  592.           }
  593.           if(++ilet > 'z') ilet = 'A';
  594.       }
  595.       ilet = 'a';
  596.       lth = COLNO - maxlth - 7;
  597.       if(lth < 10) goto clrscr;
  598.       home();
  599.       cl_end();
  600.       flags.topl = 0;
  601.       ct = 0;
  602.       for(otmp = invent; otmp; otmp = otmp->nobj) {
  603.           if(!lets || !*lets || index(lets, ilet)) {
  604.          curs(lth, ++ct);
  605.          prname(otmp, ilet, -1);
  606.           }
  607.           if(++ilet > 'z') ilet = 'A';
  608.       }
  609.       curs(lth, ct+1);
  610.       cl_end();
  611.       cmore();   /* sets morc */
  612.       /* test whether morc is a reasonable answer */
  613.       if(lets && *lets && !index(lets, morc)) morc = 0;
  614.  
  615.       home();
  616.       cl_end();
  617.       docorner(lth, ct);
  618.       return;
  619.        }
  620.    }
  621.     clrscr:
  622.    if(ct > 1) cls();
  623.    for(otmp = invent; otmp; otmp = otmp->nobj){
  624.       if(!lets || !*lets || index(lets, ilet))
  625.          prname(otmp, ilet, (ct > 1) ? 0 : 1);
  626.       if(++ilet > 'z') ilet = 'A';
  627.    }
  628.    /* tell doinvbill whether we cleared the screen */
  629.    if(!lets) doinvbill((ct > 1));
  630.    if(ct > 1){
  631.       cgetret();
  632.       docrt();
  633.    } else
  634.       morc = 0;   /* %% */
  635. }
  636.  
  637. stackobj(obj) register struct obj *obj; {
  638. register struct obj *otmp = fobj;
  639.    for(otmp = fobj; otmp; otmp = otmp->nobj) if(otmp != obj)
  640.    if(otmp->ox == obj->ox && otmp->oy == obj->oy &&
  641.       merged(obj,otmp,1))
  642.          return;
  643. }
  644.  
  645. /* merge obj with otmp and delete obj if types agree */
  646. merged(otmp,obj,lose) register struct obj *otmp, *obj; {
  647.    if(otmp->otyp == obj->otyp &&
  648.      obj->unpaid == otmp->unpaid && obj->spe == otmp->spe &&
  649.      obj->known == otmp->known && obj->dknown == otmp->dknown &&
  650.      obj->cursed == otmp->cursed &&
  651.      ((obj->olet == WEAPON_SYM && obj->otyp < BOOMERANG)
  652.      || index("%?!*",otmp->olet))){
  653.       otmp->quan += obj->quan;
  654.       otmp->owt += obj->owt;
  655.       if(lose) freeobj(obj);
  656.       obfree(obj,otmp);   /* free(obj), bill->otmp */
  657.       return(1);
  658.    } else   return(0);
  659. }
  660.  
  661. doprwep(){
  662.    if(!uwep) pline("You are empty handed.");
  663.    else prinv(uwep);
  664.    return(0);
  665. }
  666.  
  667. doprarm(){
  668.    if(!uarm && !uarmg && !uarms && !uarmh)
  669.       pline("You are not wearing any armor.");
  670.    else {
  671.       char lets[6];
  672.       register int ct = 0;
  673.  
  674.       if(uarm) lets[ct++] = obj_to_let(uarm);
  675.       if(uarm2) lets[ct++] = obj_to_let(uarm2);
  676.       if(uarmh) lets[ct++] = obj_to_let(uarmh);
  677.       if(uarms) lets[ct++] = obj_to_let(uarms);
  678.       if(uarmg) lets[ct++] = obj_to_let(uarmg);
  679.       lets[ct] = 0;
  680.       doinv(lets);
  681.    }
  682.    return(0);
  683. }
  684.  
  685. doprring(){
  686.    if(!uleft && !uright)
  687.       pline("You are not wearing any rings.");
  688.    else {
  689.       char lets[3];
  690.       register int ct = 0;
  691.  
  692.       if(uleft) lets[ct++] = obj_to_let(uleft);
  693.       if(uright) lets[ct++] = obj_to_let(uright);
  694.       lets[ct] = 0;
  695.       doinv(lets);
  696.    }
  697.    return(0);
  698. }
  699.  
  700. digit(c) char c; {
  701.    return(c >= '0' && c <= '9');
  702. }
  703.  
  704.